#pragma once
#include <pthread.h>
#include <iostream>
#include <queue>
#include <string>
#include <semaphore.h>
#include "deal.hpp"
#define PTHREAD_NUM 6
#define TASKNUM 5

template <class T>
class pthreadPool;
template <class T>
struct data
{
    std::string _name;
    pthreadPool<T> *_str;
    data(pthreadPool<T> *str) : _str(str)
    {
    }
};
template <class T>
class pthreadPool
{
public:
    friend data<T>;
    static pthreadPool<T> *get()
    {
        return _str;
    }
    void run(const T &x, int sock)
    {
        _task = x;
        _sock = sock;
    }
    void start()
    {
        for (size_t i = 0; i < PTHREAD_NUM; i++)
        {
            data<T> *p = new data<T>(this);
            if (i % 2 == 0)
                p->_name = "product";
            else
                p->_name = "consumer";
            pthread_create(tid + i, nullptr, enter, p);
        }
        std::cout << "wancheng" << std::endl;
    }
    ~pthreadPool()
    {
        pthread_mutex_destroy(&_pmtx);
        pthread_mutex_destroy(&_cmtx);
        sem_destroy(&_p);
        sem_destroy(&_c);
        for (size_t i = 0; i < PTHREAD_NUM; i++)
            pthread_join(tid[i], nullptr);
    }

private:
    int _sock = 0;
    T _task = T();
    pthread_t tid[PTHREAD_NUM];
    pthread_mutex_t _pmtx;
    pthread_mutex_t _cmtx;
    sem_t _p;
    sem_t _c;
    int _pp = 0;
    int _cc = 0;
    std::vector<T> _v;
    static pthreadPool<T> *_str;
    pthreadPool()
    {
        _v.resize(TASKNUM);
        sem_init(&_p, 0, TASKNUM);
        sem_init(&_c, 0, 0);
        pthread_mutex_init(&_cmtx, nullptr);
        pthread_mutex_init(&_pmtx, nullptr);
    }
    void product(const T x)
    {
        // 生产数据
        sem_wait(&_p);
        pthread_mutex_lock(&_pmtx);
        _v[_pp++] = x;
        _pp = _pp % TASKNUM;
        _task = T();
        pthread_mutex_unlock(&_pmtx);
        sem_post(&_c);
    }
    void consumer()
    {
        T x;
        // 消费数据
        sem_wait(&_c);
        pthread_mutex_lock(&_cmtx);
        x = _v[_cc++];
        _cc = _cc % TASKNUM;
        pthread_mutex_unlock(&_cmtx);
        sem_post(&_p);
        // 处理数据
        deal(x, _sock);
    }
    static void *enter(void *args)
    {
        data<T> *p = reinterpret_cast<data<T> *>(args);
        while (true)
        {
            if (strcmp(p->_name.c_str(), "product") == 0 && p->_str->_task != T())
                p->_str->product(p->_str->_task);
            else if (strcmp(p->_name.c_str(), "consumer") == 0)
                p->_str->consumer();
            //std::cout << "xiuxi" << std::endl;
            continue;
        }
        delete p;
        return nullptr;
    }
};
template <class T>
pthreadPool<T> *pthreadPool<T>::_str = new pthreadPool<T>();